package org.kitten.core.util;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

import org.kitten.core.io.FileHelper;

/**
 * 
 * @author sb.yin(uniquejava@gmail.com)
 * @version 1.0
 * @since 2009-11-18
 */
public class ZipUtil {
	static final int BUFFER = 2048;

	public static void main(String[] args) throws Exception {
		// String zipPath = "D:/workspace/kangel/test/commons-dbcp-1.2.1.jar";
		//
		// extractNewDir(zipPath);
		//
		// try {
		// zipSingleFolder("D:/workspace/kangel/test/commons-dbcp-1.2.1");
		// } catch (Exception e) {
		// e.printStackTrace();
		// }
		zipSingleFolder("c:/myace_temp/");
	}

	public static void zipUseCtrlA(String dirPath) throws Exception {
		File dir = new File(dirPath);
		String tempZipFileName = dir.getParent() + "/" + dir.getName() + ".zip";
		String rightZipFileName = dirPath + "/" + dir.getName() + ".zip";
		zipFolder(dirPath, tempZipFileName);
		FileHelper.copyFile(tempZipFileName, rightZipFileName);
		new File(tempZipFileName).delete();
	}

	public static void zipUseCtrlAAndMoveOut(String dirPath) throws Exception {
		File dir = new File(dirPath);
		String zipFileName = dir.getParent() + "/" + dir.getName() + ".zip";
		zipFolder(dirPath, zipFileName);
	}

	public static void zipSingleFile(String filepath) throws Exception {
		BufferedInputStream bis = null;
		FileInputStream fis = null;
		FileOutputStream fos = null;
		ZipOutputStream zos = null;
		int BUFFER = 2048;
		try {
			fos = new FileOutputStream(filepath + ".zip");
			zos = new ZipOutputStream(new BufferedOutputStream(fos));
			byte data[] = new byte[204800];
			File f = new File(filepath);
			ZipEntry entry = new ZipEntry(f.getName());
			zos.putNextEntry(entry);

			fis = new FileInputStream(f);
			bis = new BufferedInputStream(fis, BUFFER);
			int count;
			while ((count = bis.read(data, 0, BUFFER)) != -1) {
				zos.write(data, 0, count);
			}
		} catch (Exception e) {
			throw e;
		} finally {
			FileUtil.close(bis);
			FileUtil.close(fis);
			FileUtil.close(zos);
			FileUtil.close(fos);
		}
	}

	public static void zipMultiFiles(String[] files, String zipFile)
			throws Exception {
		BufferedInputStream bis = null;
		FileInputStream fis = null;
		FileOutputStream fos = null;
		ZipOutputStream zos = null;
		int BUFFER = 2048;
		try {
			fos = new FileOutputStream(zipFile);
			zos = new ZipOutputStream(new BufferedOutputStream(fos));
			byte data[] = new byte[204800];
			for (int i = 0; i < files.length; i++) {
				File f = new File(files[i]);
				ZipEntry entry = new ZipEntry(f.getName());
				zos.putNextEntry(entry);
				fis = new FileInputStream(f);
				bis = new BufferedInputStream(fis, BUFFER);
				int count;
				while ((count = bis.read(data, 0, BUFFER)) != -1) {
					zos.write(data, 0, count);
				}
			}

		} catch (Exception e) {
			throw e;
		} finally {
			FileUtil.close(bis);
			FileUtil.close(fis);
			FileUtil.close(zos);
			FileUtil.close(fos);
		}

	}

	public static void zipSingleFolder(String dirPath) throws Exception {
		File dir = new File(dirPath);
		FileOutputStream fos = null;
		ZipOutputStream zos = null;
		try {
			fos = new FileOutputStream(dir.getAbsolutePath() + ".zip");
			zos = new ZipOutputStream(fos);
			zipFolder(zos, dir, dir.getName());
		} catch (Exception e) {
			throw e;
		} finally {
			FileUtil.close(fos);
			FileUtil.close(zos);
		}
	}

	/**
	 * 
	 * @param inputFileName
	 *            输入一个文件夹
	 * @param zipFileName
	 *            输出一个压缩文件夹，打包后文件名字
	 * @throws Exception
	 */
	public static void zipFolder(String inputFileName, String zipFileName)
			throws Exception {
		zipFolder(zipFileName, new File(inputFileName), "");
	}

	public static void zipFolder(String zipFileName, File inputFile, String base)
			throws Exception {
		FileOutputStream fos = null;
		ZipOutputStream zos = null;
		try {
			fos = new FileOutputStream(zipFileName);
			zos = new ZipOutputStream(fos);
			zipFolder(zos, inputFile, base);
		} catch (Exception e) {
			throw e;
		} finally {
			FileUtil.close(fos);
			FileUtil.close(zos);
		}
	}

	private static void zipFolder(ZipOutputStream out, File f, String base)
			throws Exception {
		if (f.isDirectory()) { // 判断是否为目录
			File[] fl = f.listFiles();
			out.putNextEntry(new ZipEntry(base + "/"));
			base = base.length() == 0 ? "" : base + "/";
			for (int i = 0; i < fl.length; i++) {
				zipFolder(out, fl[i], base + fl[i].getName());
			}
		} else { // 压缩目录中的所有文件
			out.putNextEntry(new ZipEntry(base));
			FileInputStream in = new FileInputStream(f);
			int b;
			while ((b = in.read()) != -1) {
				out.write(b);
			}
			in.close();
		}
	}

	/**
	 * 模拟WINRAR点右键时的三种解压方式． <br>
	 * (1)解压到zip文件所在的目录下
	 * 
	 * @param zipPath
	 * @throws Exception
	 */
	public static void extractHere(String zipPath) throws Exception {
		File myzip = new File(zipPath);
		extract(myzip, myzip.getParent());
	}

	/**
	 * (2)新建一个与zip文件同名的目录，然后解压到那里
	 * 
	 * @param zipPath
	 * @throws Exception
	 */
	public static void extractNewDir(String zipPath) throws Exception {
		File myzip = new File(zipPath);
		String newDir = myzip.getName();
		int dot = newDir.lastIndexOf(".");
		if (dot != -1) {
			newDir = newDir.substring(0, dot);
		}
		extract(myzip, myzip.getParent() + "/" + newDir);
	}

	/**
	 * (3)解压到指定目录下
	 * 
	 * @param zipPath
	 * @param destDir
	 * @throws Exception
	 */
	public static void extract(File zipPath, String destDir) throws Exception {
		ZipFile zipFile = new ZipFile(zipPath);
		Enumeration emu = zipFile.entries();
		while (emu.hasMoreElements()) {
			ZipEntry entry = (ZipEntry) emu.nextElement();
			// 会把目录作为一个file读出一次，所以只建立目录就可以，之下的文件还会被迭代到。
			if (entry.isDirectory()) {
				new File(destDir + "/" + entry.getName()).mkdirs();
				continue;
			}
			BufferedInputStream bis = new BufferedInputStream(zipFile
					.getInputStream(entry));
			File file = new File(destDir + "/" + entry.getName());
			// 加入这个的原因是zipfile读取文件是随机读取的，这就造成可能先读取一个文件
			// 而这个文件所在的目录还没有出现过，所以要建出目录来。
			File parent = file.getParentFile();
			if (parent != null && (!parent.exists())) {
				parent.mkdirs();
			}
			FileOutputStream fos = new FileOutputStream(file);
			BufferedOutputStream bos = new BufferedOutputStream(fos, BUFFER);
			int count;
			byte data[] = new byte[BUFFER];
			while ((count = bis.read(data, 0, BUFFER)) != -1) {
				bos.write(data, 0, count);
			}
			bos.flush();
			bos.close();
			bis.close();
		}
		zipFile.close();
	}

}
